package max.ubitest.pipe.commands
{
	import flash.geom.Point;
	
	import max.ubitest.pipe.data.CellData;
	import max.ubitest.pipe.data.CellValidation;
	import max.ubitest.pipe.data.ComponentData;
	import max.ubitest.pipe.data.ComponentTypes;
	import max.ubitest.pipe.data.ReservoirSideComponentData;
	import max.ubitest.pipe.locators.CellLocator;
	import max.ubitest.pipe.locators.ComponentsLocator;
	
	import org.robotlegs.mvcs.Command;
	
	public class ValidationCommand extends Command
	{
		[Inject]
		public var compLocator:ComponentsLocator;
		[Inject]
		public var cellLocator:CellLocator;
		
		public function ValidationCommand()
		{
			super();
		}
		
		override public function execute():void{
			doValidate();
		}
		
		private function doValidate():void{
			var pump:CellData = getWaterPump();
			var i:int;
			var cell:CellData;
			if(pump == null){
				//water pump havn't mapped
				for(i = 0;i<compLocator.mappedComponents.length;i++){
					cell = compLocator.mappedComponents.getItemAt(i) as CellData;
					cell.valid = CellValidation.NONE_FITTING;
				}
				return;
			}
			var validQueue:Vector.<CellData> = new Vector.<CellData>();
			validQueue.push(pump);
			getValidQueue(validQueue);
			for each(var c:CellData in validQueue){
				validEachCell(c);
			}
			
			for(i = 0;i<compLocator.mappedComponents.length;i++){
				cell = compLocator.mappedComponents.getItemAt(i) as CellData;
				if(validQueue.indexOf(cell) < 0){
					cell.valid = CellValidation.NONE_FITTING;
				}
			}
			
			/*var cell:CellData;
			var comp:ComponentData;
			for(var i:int = 0;i<cellLocator.cells.length;i++){
				cell = cellLocator.cells.getItemAt(i) as CellData;
				if(cell.componentData == null){
					continue;
				}else{
					comp = cell.componentData;
					
				}
			}*/
		}
		
		private function validEachCell(c:CellData):void{
			if(c == null || c.componentData == null || c.componentData is ReservoirSideComponentData){
				return;
			}
			var sides:Array = c.componentData.sides;
			var p:Point;
			var near:CellData;
			var fittingCell:CellData;
			var result:String = CellValidation.NONE_FITTING;
			
			for(var i:int = 0;i<sides.length;i++){
				if(sides[i] == 1){
					if(c.componentData.type != ComponentTypes.RESERVOIR){
						p = getPoint(i);
					}else{
						p = getPointR(i);
					}
					if(p == null){
						continue;
					}
					p.x += c.x;
					p.y += c.y;
					near = cellLocator.getCellByPoint(p);
					if(near == null){
						continue;
					}
					fittingCell = near.componentData is ReservoirSideComponentData ? near.componentData.cellData:near;
					
					if(near != null){
						if(near.componentData == null){
							continue;
						}else{
							var fittingSideIndex:int = -1;
							
							if(c.componentData.type == ComponentTypes.RESERVOIR){
								switch(i){
									case 1://check near's bottom side
										fittingSideIndex = near.componentData is ReservoirSideComponentData ? 5:2;
										break;
									case 3://check near's left side
										fittingSideIndex = near.componentData is ReservoirSideComponentData ? 7:3;
										break;
									case 5://check near's top side
										fittingSideIndex = near.componentData is ReservoirSideComponentData ? 1:0;
										break;
									case 7://check near's right side
										fittingSideIndex = near.componentData is ReservoirSideComponentData ? 3:1;
										break;
								}
							}else{
								switch(i){
									case 0://check near's bottom side
										fittingSideIndex = near.componentData is ReservoirSideComponentData ? 5:2;
										break;
									case 1://check near's left side
										fittingSideIndex = near.componentData is ReservoirSideComponentData ? 7:3;
										break;
									case 2://check near's top side
										fittingSideIndex = near.componentData is ReservoirSideComponentData ? 1:0;
										break;
									case 3://check near's right side
										fittingSideIndex = near.componentData is ReservoirSideComponentData ? 3:1;
										break;
								}
							}
							
							if(fittingSideIndex >= 0){
								if(fittingCell.componentData.sides[fittingSideIndex] == 0){
									result = CellValidation.INVALID;
								}else{
									result = CellValidation.VALIDE;
								}
							}
							if(result == CellValidation.INVALID){
								break;
							}
						}
					}
				}
			}
			c.valid = result;
		}
		
		private function getValidQueue(queue:Vector.<CellData>):void{
			if(queue == null){
				return;
			}
			var copy:Vector.<CellData> = queue.concat();
			var temp:Vector.<CellData> = new Vector.<CellData>();
			for each(var c:CellData in queue){
				temp = temp.concat(getLinkedCells(c));
			}
			//push none-duplicate cell data into queue
			while(temp.length > 0){
				c = temp.pop();
				if(queue.indexOf(c) < 0 && c.componentData != null){
					queue.push(c);
				}
			}
			if(copy.length != queue.length){
				getValidQueue(queue);
			}else{
				return;
			}
		}
		
		private function getLinkedCells(cell:CellData):Vector.<CellData>{
			var cells:Vector.<CellData> = new Vector.<CellData>();
			if(cell.componentData == null){
				return cells;
			}
			if(cell.componentData is ReservoirSideComponentData){
				return cells;
			}
			var realCell:CellData = cell;
			/*if(cell.componentData is ReservoirSideComponentData){
				//it's a border of reservoir component
				realCell = cell.componentData.cellData;
			}else{
				realCell = cell;
			}*/
			var near:CellData;
			var i:int;
			var p:Point;
			var sides:Array;
			sides = realCell.componentData.sides;
			for(i = 0;i<sides.length;i++){
				if(sides[i] == 1){
					if(realCell.componentData.type != ComponentTypes.RESERVOIR){
						p = getPoint(i);
					}else{
						p = getPointR(i);
					}
					if(p == null){
						continue;
					}
					p.x += realCell.x;
					p.y += realCell.y;
					near = cellLocator.getCellByPoint(p);
					if(near){
						if(near.componentData && near.componentData is ReservoirSideComponentData){
							cells.push(near.componentData.cellData);
						}else{
							cells.push(near);
						}
					}
				}
			}
			return cells;
		}
		
		private function getPointR(i:int):Point{
			var p:Point = new Point();
			switch(i){
				case 1:
					p.x = 0;
					p.y = -2;
					break;
				case 3:
					p.x = 2;
					p.y = 0;
					break;
				case 5:
					p.x = 0;
					p.y = 2;
					break;
				case 7:
					p.x = -2;
					p.y = 0;
					break;
				default:
					p = null;
					break;
			}
			return p;
		}
		
		private function getPoint(i:int):Point{
			var p:Point = new Point();
			switch(i){
				case 0:
					p.x = 0;
					p.y = -1;
					break;
				case 1:
					p.x = 1;
					p.y = 0;
					break;
				case 2:
					p.x = 0;
					p.y = 1;
					break;
				case 3:
					p.x = -1;
					p.y = 0;
					break;
				default:
					p.x = 0;
					p.y = -1;
					break;
			}
			return p;
		}
		
		private function getWaterPump():CellData{
			var cell:CellData;
			var r:CellData;
			for(var i:int = 0;i<cellLocator.cells.length;i++){
				cell = cellLocator.cells.getItemAt(i) as CellData;
				if(cell.componentData == null){
					continue;
				}else{
					if(!(cell.componentData is ReservoirSideComponentData) && cell.componentData.type == ComponentTypes.WATER_PUMP){
						r = cell;
						break;
					}
				}
			}
			return r;
		}
	}
}